package clases;

import java.io.FileOutputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Calendar;

    
    
    
    
/**
 * Clase para modelar las consultas relacionadas
 * con totalizaciones sobre determinados datos
 * yacentes en las matrices manejadas por el
 * Sistema de Gestión de la Comisión de Planificación
 * @version 1.0
 * @author Jesus Martinez
 */
public class Totalizacion extends Root implements Serializable, Reportable {
    private Integer idTotalizacion;
    private Matriz matriz = new Matriz(); //Matriz a ser totalizada.
    private String nombre = ""; //Nombre de la totalizacion = concatenacion de "condicion".
    private ArrayList<Celda> celdasATotalizar = new ArrayList<Celda>(); //Filas resultantes del filtrado.
    private ArrayList<CondicionTotalizacion> condicion = new ArrayList<CondicionTotalizacion>(); //ArrayList con los nombres de las celdas que se deben buscar.
    private int numeroFilas;
    private Integer idMatriz = null; //Id de la matriz que se esta totalizando.
    private String tipoMatriz = "";
    //private boolean ajuste = false; //True si hay que tomar en cuenta los datos de ajuste.
    //private boolean planificacion = false; //True si hay que tomar en cuenta los datos de planificacion.
    //private boolean ejecucion = false; //True si hay que tomar en cuenta los datos de ejecucion.
    /**
     * Constructor de la clase. Permite crear una nueva
     * totalizacion vacia.
     */
    public Totalizacion() {
    }

    /**
     * Constructor de la clase. Permite crear una totalizacion
     * utilizando la condicion c para filtrar las filas de la
     * matriz m.
     * @param m Matriz m a ser totalizada.
     * @param c 
     */
    public Totalizacion(Matriz m, ArrayList<CondicionTotalizacion> c) {
        this.matriz = m;
        this.idMatriz = m.getIdMatriz();
        this.condicion = c;    
    }
    
    /**
     * Función que retorna las filas utilizadas en el cálculo de esta
     * totalización.
     * @return
     */
    public ArrayList<Celda> getCeldasATotalizar() {
        return celdasATotalizar;
    }

    /**
     * Función que almacena las filas necesarias para llevar a cabo 
     * esta totalización.
     * @param filas
     */
    public void setCeldasATotalizar(ArrayList<Celda> celdasATotalizar) {
        this.celdasATotalizar = celdasATotalizar;
    }

    public Integer getIdMatriz() {
        return idMatriz;
    }

    public void setIdMatriz(Integer idMatriz) {
        this.idMatriz = idMatriz;
    }

    /**
     * Función que devuelve el nombre de esta totalización.
     * @return String con el nombre de la totalización.
     */
    public String getNombre() {
        return nombre;
    }

    /**
     * Función que fija el nombre de la totalización.
     * @param nombre
     */
    public void setNombre(String nombre) {
        this.nombre = nombre;
    }

    /**
     * Función que retorna el número de filas asociadas
     * a esta totalización.
     * @return 
     */
    public int getNumeroFilas() {
        return numeroFilas;
    }
    
    /**
     * 
     * @param numeroFilas
     *
    public void setNumeroFilas(int numeroFilas) {
        this.numeroFilas = numeroFilas;
    }*/
    
    /*
     * Metodo auxiliar que filtra las filas de una matriz dependiendo de
     * si cumplen con una determinada condicion.
     */
    public void filtrar() {
        
        //Si no hay condiciones que evaluar, simplemente se totalizara
        //toda la matriz.
        ArrayList<Fila> filas = this.matriz.obtenerFilas();
        if (this.condicion.isEmpty()) {
            System.out.println("Condicion esta vacio");
            int ultimaPosicion = filas.get(0).getCeldas().size() - 2;
            
            for(Fila f : filas) {
                Celda c = f.getCeldas().get(ultimaPosicion);
                this.celdasATotalizar.add(c);
            }
            
            return;
        }
        
        //Obtendre el id de la columna llamada Cantidad, pues alli estara
        //guardada la informacion que deseo totalizar.
        Integer idCantidad = new Integer(-1);
        for (Columna col : this.matriz.getColumnas()) {
            if(col.getNombre().toLowerCase().compareTo("cantidad") == 0) {
                idCantidad = col.getIdColumna();
                break;
            }
        }
        
        //Para cada fila, voy a verificar que cumple con todas las condiciones y,
        //de ser asi, me quedare con a ultima celda, la cual contiene el valor
        //que se utilizara para totalizar.
        while(!filas.isEmpty()) {
            
            boolean filaValida = true;
            
            Fila f = filas.get(0);
           
            //Hago una copia de la lista de condiciones para poder trabajarla
            //con mas comodidad.
            ArrayList<CondicionTotalizacion> copiaCondiciones = clonarCondicion(this.condicion);

            //Mientras no se hayan satisfecho todas las condiciones
            while(!copiaCondiciones.isEmpty()) {
                
                CondicionTotalizacion cond = copiaCondiciones.get(0);
                System.out.println("Condicion "+ cond.getCondicion());
                //Si la condicion sobre esta columna no existe, entonces se 
                //elimina
                if (cond.getCondicion().compareTo("-1") == 0) {
                    copiaCondiciones.remove(cond);
                    continue;
                }
                
                //Busco en todas las celdas de esta fila una que satisfaga
                //la condicion actual.
                for (Celda c : f.getCeldas()) {
                    
                    //Si el llegue a la columna a la que corresponde esta 
                    //condicion...
                    if (cond.getIdColumna().equals(c.getIdColumna())) {
                        
                        //...verifico que satisfaga la condicion. Si es asi, 
                        //quita esta condicion de la lista de condiciones
                        //pendientes y dejo de buscar.
                        if (c.getNombre().compareTo(cond.getCondicion()) == 0) {
                            copiaCondiciones.remove(cond);
                            System.out.println("c.getNombre "+ c.getNombre());
                            filaValida = true;
                        } else {
                            //Si no satisface, entonces he encontrado una celda
                            //de esta fila que no cumple con una de las
                            //condiciones y como para que una fila entre
                            //dentro de una totalizacion ha de cumplir
                            //con TODAS las totalizaciones, entonces esta fila
                            //no es valida.
                            System.out.println("(falso) c.getNombre "+ c.getNombre());
                            filaValida = false;
                        }
                        break;
                    }
                }
                
                //Si esta fila no es valida, entones dejo de verificar otras
                //condiciones...
                if (!filaValida) {
                    System.out.println("Fila invalida");
                    break;
                }
            }
            
            
            //Si la fila es valida, entonces obtengo la columna cuyo nombre es "Cantidad",
            //pues, alli reside el dato que quiero usar en la totalizacion.
            if (filaValida) {
                for(Celda c : f.getCeldas()) {
                   if (c.getIdColumna().equals(idCantidad)) {
                       System.out.println("Columna celdas validas y celda valida "+ c.getIdColumna()+" "+c.getDato().getValor());
                       this.celdasATotalizar.add(c);
                        break;
                    }
                }
            }
            
            filas.remove(f);
            
        }
    }

    public ArrayList<CondicionTotalizacion> getCondicion() {
        return condicion;
    }

    public void setCondicion(ArrayList<CondicionTotalizacion> condicion) {
        this.condicion = condicion;
    }

    public Matriz getMatriz() {
        return matriz;
    }

    public void setMatriz(Matriz matriz) {
        this.matriz = matriz;
    }
    
   
    /**
     * Funcion que ejecuta la totalizacion de las celdas resultantes de filtrar
     * las filas de esta matriz con la condicion de entrada.
     * @return Numero real con el resultado de la totalizacion. En este caso
     *         particular, totalizar = sumar
     */
    public double totalizar() {
        double total = 0.0;
        //for (Celda c : this.celdasATotalizar) {
          //  total += Double.parseDouble(c.getDato().getValor());
        //}
        
        for (Celda c : this.celdasATotalizar) {
            total += Double.parseDouble(c.getDato().getValor());
        }
        
        return total;
    }
    
    /* Metodo para calcular el trimestre actual dependiendo
     * del mes.
     
    private int calcularTrimestreActual() {
      Calendar fecha = Calendar.getInstance();  
      
      int mes = fecha.get(Calendar.MONTH);
      
      if (mes >=0 && mes <= 2)
      {
          return 1;
      } else if(mes >= 3 && mes <= 5) {
          return 2;
      } else if(mes >= 6 && mes <= 8) {
          return 3;
      } else {
          return 4;
      }
    } */

    public Integer getIdTotalizacion() {
        return idTotalizacion;
    }

    public void setIdTotalizacion(Integer idTotalizacion) {
        this.idTotalizacion = idTotalizacion;
    }
    
    public CondicionTotalizacion getCondi(int index) {
        while (this.condicion.size() <= index) {
            this.condicion.add(new CondicionTotalizacion());
        }
        return this.condicion.get(index);
    }

    public String getTipoMatriz() {
        return tipoMatriz;
    }

    public void setTipoMatriz(String tipoMatriz) {
        this.tipoMatriz = tipoMatriz;
    }

    @Override
    public void imprimirArchivoTabla(FileOutputStream f) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public void imprimirArchivoDoc(FileOutputStream f) {
        throw new UnsupportedOperationException("Not supported yet.");
    }
    
    public static ArrayList<CondicionTotalizacion> clonarCondicion(ArrayList<CondicionTotalizacion> condicion) {
        ArrayList<CondicionTotalizacion> clonada = new ArrayList<CondicionTotalizacion>(condicion.size());
        for(CondicionTotalizacion item: condicion){
            clonada.add(item);
        }
    return clonada;
    }
}
